#include "bsp_port.h"
#include "User_App.h"

#if 0
void bsp_uart_SendData(Bsp_Uart_t Uart, uint8_t *data, uint16_t datalen)
{
    USART_TypeDef *UART;
    uint32_t Channel;

    switch (Uart)
    {
    case BSP_UART1:
        UART = USART1;
        Channel = LL_DMA_CHANNEL_1;
        break;

    case BSP_UART2:
        UART = USART2;
        Channel = LL_DMA_CHANNEL_2;
        break;

        //    case BSP_UART3:
        //        UART = USART3;
        //        Channel = LL_DMA_CHANNEL_3;
        //        break;

        //    case BSP_UART4:
        //        UART = USART4;
        //        Channel = LL_DMA_CHANNEL_4;
        //        break;

    default:
        break;
    }

    LL_DMA_SetMemoryAddress(DMA1, Channel, (uint32_t)data);
    LL_DMA_SetDataLength(DMA1, Channel, datalen);
    LL_USART_EnableDMAReq_TX(UART);
    /* Enable DMA Channel Tx */
    LL_DMA_EnableChannel(DMA1, Channel);
}
/*  @brief  串口发送函数
    @param  Buf
            要发送的数组
    @param  length
            数据组的长度
    @return 无
    @property 非DMA方式
*/
void bsp_USART_SendBytes(uint8_t *Buf, uint8_t length)
{
    bsp_mDelay(5);
    for (uint8_t i = 0; i < length; i++)
    {
        while (LL_USART_IsActiveFlag_TC(USART2) != 1)
            ;
        LL_USART_TransmitData8(USART2, Buf[i]); // 发送数据
    }
    bsp_mDelay(2);
}

/*  @brief  串口以DMA方式发送数据
    @param  *databuf
            要发送的数据
    @param  datalen
            数据长度
    @return 无
    @property 无
*/
void bsp_USART_DMA_SendBytes(uint8_t *Buf, uint16_t Len)
{
#if 1

#if EnReDe485Pin
    MX_485_TX_MODEL;
#endif
    while (LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1)) // 检查DMA通道是否启用或禁用
        ;
    LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)Buf); // 告诉DMA它要发送数据的地址
    LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, Len);              // 告诉DMA它要发送的数据长度
    LL_USART_EnableDMAReq_TX(USART1);                               // 让USART开启DMA模式传输模式
    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);                   // 启用DMA通道
#endif

将下方代码放到串口初始化中
  LL_USART_EnableIT_RXNE(USART1);                                                                                   // 使能串口中断
  LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);                                                                       // 启用DMA传输完成中断�??
  LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_1, LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_TRANSMIT)); // 配置DMA传输的目的地�??

将下方代码放到DMA中断中
 if (LL_DMA_IsActiveFlag_TC1(DMA1)) // 获取通道的传输完成标志。这里的LL_DMA_IsActiveFlag_TC2需要根据配置填写
  {
    LL_DMA_ClearFlag_TC1(DMA1);                    // 清除通道的传输完成标志
    LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); // 禁用DMA通道
    LL_USART_DisableDMAReq_TX(USART1);             // 禁用DMA模式传输
  }
}


// 重定向 printf();打开魔法棒里的开关
int fputc(int ch, FILE *stream)
{
    while (!LL_USART_IsActiveFlag_TXE(USART2))
    {
        ;
    }
    LL_USART_TransmitData8(USART2, (uint8_t)ch);
    return ch;
}
#endif

/*  @brief  控制 循环泵
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Circulate_Pump(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_03_GPIO_Port, OUTPUT_03_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_03_GPIO_Port, OUTPUT_03_Pin);
    }
}
/*  @brief  控制 排水泵
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Expel_Pump(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_05_GPIO_Port, OUTPUT_05_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_05_GPIO_Port, OUTPUT_05_Pin);
    }
}
/*  @brief  控制 补水泵
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Supply_Pump(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_06_GPIO_Port, OUTPUT_06_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_06_GPIO_Port, OUTPUT_06_Pin);
    }
}
/*  @brief  控制 氧气泵
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Oxygen_Pump(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_07_GPIO_Port, OUTPUT_07_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_07_GPIO_Port, OUTPUT_07_Pin);
    }
}
/*  @brief  控制 灯光
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Lamp(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_08_GPIO_Port, OUTPUT_08_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_08_GPIO_Port, OUTPUT_08_Pin);
    }
}
/*  @brief  控制 鱼缸底部灯光
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Down_Lamp(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_08_GPIO_Port, OUTPUT_08_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_08_GPIO_Port, OUTPUT_08_Pin);
    }
}
/*  @brief  控制 喂食器
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Feed_Device(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_06_GPIO_Port, OUTPUT_06_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_06_GPIO_Port, OUTPUT_06_Pin);
    }
}
/*  @brief  控制 鱼缸加热
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Fishbowl_Heat(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_02_GPIO_Port, OUTPUT_02_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_02_GPIO_Port, OUTPUT_02_Pin);
    }
}
/*  @brief  控制 补水桶加热
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_SupplyTub_Heat(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_08_GPIO_Port, OUTPUT_08_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_08_GPIO_Port, OUTPUT_08_Pin);
    }
}
/*  @brief  控制 造浪泵
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 无
*/
void bsp_Ctrl_Wave_Pump(switch_e state)
{
    if (state == ON_s)
    {
        LL_GPIO_SetOutputPin(OUTPUT_01_GPIO_Port, OUTPUT_01_Pin);
    }
    else if (state == OFF_s)
    {
        LL_GPIO_ResetOutputPin(OUTPUT_01_GPIO_Port, OUTPUT_01_Pin);
    }
}

/*  @brief  获得 补水水位状态
    @param  state
             OFF_s 关闭 ON_s 打开
    @return 无
    @property 水位到达1、未到达0
*/
uint8_t bsp_Get_Waterline(void)
{
    return (LL_GPIO_IsInputPinSet(INPUT_01_GPIO_Port, INPUT_01_Pin));
}

// 定义延时函数
void bsp_Delay_us(uint32_t us)
{
    uint32_t ticks = us * (SystemCoreClock / 10000000); // 计算需要的SysTick时钟周期数
    SysTick->LOAD = ticks - 1;                          // 设置重载值
    SysTick->VAL = 0;                                   // 清空当前值
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;            // 开启SysTick计数器
    while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0)
        ;              // 等待计数完成
    SysTick->CTRL = 0; // 关闭SysTick计数器
}
/** @brief  设置对应位数据
 *  @param  data 数据初始值
 *  @param  Bit_Lie 对应位所在的位置
 *  @param  Bit_Num 所占位的数量
 *  @param  set_Data 将对应位设置的数据
 *  @return 经过处理的数据 data
 *  @property 无
 */
uint8_t bsp_set_bit(uint8_t data, uint8_t Bit_Lie, uint8_t Bit_Num, uint8_t set_Data)
{
    // 生成用于清除指定位置和位数的掩码
    uint8_t clear_mask = ~((0xFF >> (8 - Bit_Num)) << Bit_Lie);
    // 清除指定位置和位数的数据
    data &= clear_mask;
    // 提取 set_Data 的低 Bit_Num 位并左移到指定位置
    uint8_t shifted_set_data = (set_Data & (0xFF >> (8 - Bit_Num))) << Bit_Lie;
    // 将处理后的 set_Data 合并到 data 中
    data |= shifted_set_data;
    return data;
}
/** @brief  获取对应位数据
 *  @param  data 原始数据
 *  @param  Bit_Lie 对应位所在的位置
 *  @param  Bit_Num 所占位的数量
 *  @return 想要得到的数据
 *  @property 无
 */
uint8_t bsp_get_bit(uint8_t data, uint8_t Bit_Lie, uint8_t Bit_Num)
{
    // 生成掩码，用于提取指定位置和位数的数据
    uint8_t mask = (0xFF >> (8 - Bit_Num)) << Bit_Lie;
    // 提取指定位置的数据
    uint8_t extracted = data & mask;
    // 将提取的数据右移到最低位
    return extracted >> Bit_Lie;
}
// 看门狗喂狗
void bsp_IWDG_ReloadCounter(void)
{
#if IWDG_FLAG
    LL_IWDG_ReloadCounter(IWDG); // 喂狗
#endif
}
